#include <mono/event/event_loop_thread_pool.h>

namespace mono {

EventLoopThreadPool::EventLoopThreadPool(EventLoopPtr &baseLoop, const std::string &name)
  : _baseLoop(baseLoop),
    _started(false),
    _numThreads(0),
    _next(0),
    _name(name)
{
}

EventLoopThreadPool::~EventLoopThreadPool()
{

}

void EventLoopThreadPool::start(const ThreadInitCallback& cb)
{
    assert(!_started);
    //_baseLoop->assertInLoopThread();

    _started = true;

    for (int i = 0; i < _numThreads; ++i) {
        EventLoopThreadPtr t(new EventLoopThread(cb, _name));
        _threads.push_back(t);
        _loops.push_back(t->start());
    }
    if (_numThreads == 0 && cb) {
        cb(_baseLoop);
    }
}

EventLoopPtr EventLoopThreadPool::getNextLoop()
{
    _baseLoop->assertInLoopThread();
    assert(_started);
    EventLoopPtr loop = _baseLoop;

    if (!_loops.empty()) {
        // round-robin
        loop = _loops[_next];
        ++_next;
        if (_next >= static_cast<int>(_loops.size())) {
            _next = 0;
        }
    }
    return loop;
}

EventLoopPtr EventLoopThreadPool::getLoopForHash(size_t hashCode)
{
    _baseLoop->assertInLoopThread();
    EventLoopPtr loop = _baseLoop;

    if (!_loops.empty()) {
        loop = _loops[hashCode % _loops.size()];
    }
    return loop;
}

std::vector<EventLoopPtr> EventLoopThreadPool::getAllLoops()
{
    _baseLoop->assertInLoopThread();
    assert(_started);
    if (_loops.empty()) {
        return std::vector<EventLoopPtr>(1, _baseLoop);
    } else {
        return _loops;
    }
}

}

